# coding=utf-8
import socket
import os
import time
import pickle
import random
from pymongo import MongoClient
from bson.objectid import ObjectId


class Query(object):
    def __init__(self, db, table, addr):
        self.conn = MongoClient(addr[0], addr[1])
        self.db = self.conn[db][table]
        self.db_name = db

    def get_all(self):
        """查询全部"""
        self.workers =[x for x in self.db.find()]

    def update(self):
        self.get_all()
        
        index = 0
        for worker in self.workers:
            print worker.keys()
            print 'worker 下标', index
            print 'worker _id:', worker['_id']
            print 'worker 进程id:',int(worker['pid'])
            print 'worker ip:',worker['ip']
            print 'worker 状态:', worker['status']
            print 'worker 执行任务总量', len(worker['log'])
            print "\n\n"
            index += 1

        print "如需详细查询单个worker具体历史记录请使用 get_one(下标), 或者直接查询 self.workers[下标] 方法"

    def get_one(self, index):
        for log in self.workers[index]['log']:
            time_local = time.localtime(log['start'])
            start = time.strftime("%Y-%m-%d %H:%M:%S",time_local)
            time_local = time.localtime(log['end'])
            end = time.strftime("%Y-%m-%d %H:%M:%S",time_local)
            print '任务开始时间:', start
            print '任务结束时间:', end
            print '任务执行对象:', pickle.loads(log['def']).__name__
            print '任务执行参数:', log['args']
            print '任务执行结果:', log['result']
            print '任务执行上级表对象:', log['task_parent']
            print '\n\n'

def query():
    database_db = 'Colony'  #  使用的数据库名字
    worker_table = 'worker'  #　使用总任务表名字
    addr = ('0.0.0.0', 27017)  # mongdb地址
    q = Query( database_db, worker_table, addr)
    return q


class Fmain(object):
    def __init__(self, fun, space, mac_evals, algo, args, db, table, addr):
        """append base attribute"""
        self.fun = fun
        self.space = space 
        self.mac_evals = mac_evals
        self.algo = algo
        self.args = args
        self.pid = os.getpid()

        self.conn = MongoClient(addr[0], addr[1])
        self.db = self.conn[db][table]
        self.db_name = db




    def start(self):
        task = dict()  #  task object

        task['status'] = 'going'
        task['start'] = time.time()
        task['def'] = pickle.dumps(self.fun)
        task['log'] = list()
        task['name'] = str(self.pid + round(random.random(), 4))

        self.task = task
        
        # task table manage
        self.task_table = self.conn[self.db_name][task['name']]

        # inset to task table
        task_table_list = list()
        for args in self.args:
            info = dict()
            info['status'] = 'new'
            info['def'] = pickle.dumps(self.fun)
            info['result'] = None
            info['args'] = args
            task_table_list.append(info)

        self.task_table.insert(task_table_list)
        
        # start task
        self.db.insert(task)
        


    def plan(self):
        self.task = self.db.find_one({'name':self.task['name']})
        task_table = self.task_table.find()
        task_table_list = [task for task in task_table]

        self.new = list()
        self.end = list()
        self.going = list()
        self.error = list()

        for task in task_table_list:
            if task['status'] == 'new':
                self.new.append(task)
            elif task['status'] == 'going':
                self.going.append(task)
            elif task['status'] == 'end':
                self.end.append(task)
            elif task['status'] == 'error':
                self.error.append(task)

        print 'worker number: %d'%len(self.task['log'])
        print 'count task: %d'%self.mac_evals
        print 'new: %d'%len(self.new)
        print 'end: %d'%len(self.end)
        print 'going: %d'%len(self.going)
        print 'error: %d'%len(self.error)

        self.finish = list()
        for info in self.end:
            self.finish.append({'result':info['result'], 'args': info['args']})

        
    def join(self):
        """wait for end"""

        while True:
            self.task = self.db.find_one({'name':self.task['name']})
            if self.task['status'] != 'going':
                print 'all task end'
                self.plan()
                return 'end'
            time.sleep(0.2)


def random_alg(space, mac_evals):
    """
    space = {
        args1 : []
        args2 : []
        ...
    }
    
    """
    info = list()
    for x in range(mac_evals):
        args = dict()
        for key, value in space.items():
            args[key] = random.sample(value, 1)[0]
        info.append(args)
    return info

def fmain(fun, space, mac_evals, algo=random_alg):
    """
    fun: 方法
    space: 选参对象
    mac_evals: 选参次数
    alog: arithmetic
    """
    database_db = 'Colony'  #  使用的数据库名字
    parent_table = 'ParentTable'  #　使用总任务表名字
    addr = ('0.0.0.0', 27017)  # mongdb地址
    args = algo(space, mac_evals)
    return Fmain(fun, space, mac_evals, algo, args, database_db, parent_table, addr)


